#include <crt_mutex.h>


#if (TARGET_OS == OS_WINDOWS)

int _mutex_init(_mutex_t* mutex) {
	InitializeCriticalSection(mutex);
	return 0;
}

int	 _mutex_init_recursive(_mutex_t* mutex) {
	return _mutex_init(mutex);
}

void _mutex_destroy(_mutex_t* mutex) {
	DeleteCriticalSection(mutex);
}

int _mutex_trylock(_mutex_t* mutex) {
	int iRet = TryEnterCriticalSection(mutex) > 0 ? 0 : -1;
	return iRet;
}

void _mutex_lock(_mutex_t* mutex) {
	EnterCriticalSection(mutex);
}
void _mutex_unlock(_mutex_t* mutex) {
	LeaveCriticalSection(mutex);
}


#elif (TARGET_OS == OS_POSIX)

int _mutex_init(_mutex_t* mutex) {
	return pthread_mutex_init(mutex, NULL);
}

int	_mutex_init_recursive(_mutex_t* mutex) {
	pthread_mutexattr_t attr;
	int err;

	if (pthread_mutexattr_init(&attr))
		abort();

	if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE))
		abort();

	err = pthread_mutex_init(mutex, &attr);

	if (pthread_mutexattr_destroy(&attr))
		abort();

	return err;
}

void _mutex_destroy(_mutex_t* mutex) {
    
    int err;
    err = pthread_mutex_destroy(mutex);
    
    if (err) {
        if (err == EAGAIN)
            abort();
        else {
            if (err == EBUSY)
                abort();
        }
    }
}

void _mutex_lock(_mutex_t* mutex) {
	if (pthread_mutex_lock(mutex))
		abort();
}

int _mutex_trylock(_mutex_t* mutex) {
	int err;

	err = pthread_mutex_trylock(mutex);
	if (err) {
		if (err != EBUSY && err != EAGAIN)
			abort();
		return -1;
	}
	return 0;
}

void _mutex_unlock(_mutex_t* mutex) {
	if (pthread_mutex_unlock(mutex))
		abort();
}

#elif (TARGET_OS == OS_DARWIN)

int _mutex_init(_mutex_t* mutex) {
    return pthread_mutex_init(mutex, NULL);
}

int    _mutex_init_recursive(_mutex_t* mutex) {
    pthread_mutexattr_t attr;
    int err;

    if (pthread_mutexattr_init(&attr))
        abort();

    if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE))
        abort();

    err = pthread_mutex_init(mutex, &attr);

    if (pthread_mutexattr_destroy(&attr))
        abort();

    return err;
}

void _mutex_destroy(_mutex_t* mutex) {
    
    int err;
    err = pthread_mutex_destroy(mutex);
    
    if (err) {
        if (err == EAGAIN)
            abort();
        else {
            if (err == EBUSY)
                abort();
        }
    }

}

void _mutex_lock(_mutex_t* mutex) {
    if (pthread_mutex_lock(mutex))
        abort();
}

int _mutex_trylock(_mutex_t* mutex) {
    int err;

    err = pthread_mutex_trylock(mutex);
    if (err) {
        if (err != EBUSY && err != EAGAIN)
            abort();
        return -1;
    }
    return 0;
}

void _mutex_unlock(_mutex_t* mutex) {
    if (pthread_mutex_unlock(mutex))
        abort();
}



#endif



